﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

using EdgeStatz.ESSystems.Objects;

namespace EdgeStatz.ModelEngine.FolderTools
{
    class FolderToolsXml
    {
        #region Instance Variable & Properties
        
        private string xmlFilePath = null;

        List<FolderDefinition> folders = new List<FolderDefinition> { };
        List<EnumFolderDefinition> enums = new List<EnumFolderDefinition> { };
        
        public string XmlFilePath
        {
            set { xmlFilePath = value; }
            get { return xmlFilePath; }
        }
        
        public FolderDefinition[] Folders
        {
            set 
            {
                folders = new List<FolderDefinition> { };
                folders.AddRange(value);
            }
            get { return folders.ToArray(); }
        }

        public EnumFolderDefinition[] EnumFolders
        {
            set
            {
                enums = new List<EnumFolderDefinition> { };
                enums.AddRange(value);
            }
            get { return enums.ToArray(); }
        }
        #endregion

        public FolderToolsXml(string path)
        {
            using (XmlTextReader xmlReader = new XmlTextReader(path))
                xmlFilePath = xmlReader.BaseURI;
            Init();
        }
        
        #region Folder Methods
        public bool FolderExistsByName(string name)
        {
            foreach (FolderDefinition fl in Folders)
                if (fl.Name.Equals(name))
                    return true;
            return false;
        }

        public bool FolderExistsByTable(string tablename)
        {
            foreach (FolderDefinition fl in Folders)
                if (fl.TableName.Equals(tablename))
                    return true;
            return false;
        }

        public FolderDefinition GetFolderbyName(string name)
        {
            foreach (FolderDefinition fl in Folders)
                if (fl.Name.Equals(name))
                    return fl;
            return null;
        }

        public FolderDefinition GetFolderByTable(string tablename)
        {
            foreach (FolderDefinition fl in Folders)
                if (fl.TableName.Equals(tablename))
                    return fl;
            return null;
        }

        public void AddFolder(FolderDefinition value)
        {
            folders.Add(value);
        }

        public void InsertFolder(int index, FolderDefinition value)
        {
            folders.Insert(index, value);
        }

        public void RemoveFolderByName(string name) 
        {
            foreach (FolderDefinition fl in Folders)
                if (fl.Name.Equals(name))
                    folders.Remove(fl);
        }
        
        public void RemoveFolderByTableName(string tablename) 
        {
            foreach (FolderDefinition fl in Folders)
                if (fl.TableName.Equals(tablename))
                    folders.Remove(fl);
        }

        #endregion

        #region Enum Methods
        public bool EnumFolderExistsByName(string name)
        {
            foreach (EnumFolderDefinition efl in EnumFolders)
                if (efl.Name.Equals(name))
                    return true;
            return false;
        }

        public bool EnumFolderExistsByTable(string tablename)
        {
            foreach (EnumFolderDefinition efl in EnumFolders)
                if (efl.TableName.Equals(tablename))
                    return true;
            return false;
        }

        public EnumFolderDefinition GetEnumFolderbyName(string name)
        {
            foreach (EnumFolderDefinition efl in EnumFolders)
                if (efl.Name.Equals(name))
                    return efl;
            return null;
        }

        public EnumFolderDefinition GetEnumFolderByTable(string tablename)
        {
            foreach (EnumFolderDefinition efl in EnumFolders)
                if (efl.TableName.Equals(tablename))
                    return efl;
            return null;
        }

        public void AddEnumFolder(EnumFolderDefinition value)
        {
            enums.Add(value);
        }

        public void InsertEnumFolder(int index, EnumFolderDefinition value)
        {
            enums.Insert(index, value);
        }

        public void RemoveEnumFolderByName(string name)
        {
            foreach (EnumFolderDefinition efl in EnumFolders)
                if (efl.Name.Equals(name))
                    enums.Remove(efl);
        }

        public void RemoveEnumFolderByTableName(string tablename)
        {
            foreach (EnumFolderDefinition efl in EnumFolders)
                if (efl.TableName.Equals(tablename))
                    enums.Remove(efl);
        }

        #endregion

        #region Read & Write
        private void Init()
        {
            if (XmlFilePath == null)
                throw new NullReferenceException("Error: Model file not selected.");

            XmlDocument myXmlDocument = new XmlDocument();
            myXmlDocument.Load(XmlFilePath);

            XmlNode rootNode;
            rootNode = myXmlDocument.DocumentElement;

            folders.Clear();
            enums.Clear();

            foreach (XmlNode node1 in rootNode.ChildNodes)
            {
                if (node1.Name.ToUpper() == "STRUCTURE")
                {
                    foreach (XmlNode node2 in node1.ChildNodes)
                    {
                        if (node2.Name.ToUpper() == "FOLDER")
                        {
                            string name = node2.Attributes["Name"] == null ? null : node2.Attributes["Name"].Value;
                            string table = node2.Attributes["Table"] == null ? null : node2.Attributes["Table"].Value;
                            
                            FolderLevel level = FolderLevel.One;
                            switch (node2.Attributes["Level"].Value)
                            {
                                case "1":
                                    level = FolderLevel.One;
                                    break;
                                case "2":
                                    level = FolderLevel.Two;
                                    break;
                                case "3":
                                    level = FolderLevel.Three;
                                    break;
                                case "4":
                                    level = FolderLevel.Four;
                                    break;
                            }
                            if (level == FolderLevel.Four)
                            {
                                folders.Add(new FolderDefinition(name, table));
                            }
                            else
                            {
                                FolderDefinition nxtfolder = new FolderDefinition(name, table, level,
                                        node2.Attributes["Display"] == null ? null : node2.Attributes["Display"].Value,
                                        node2.Attributes["Value"] == null ? null : node2.Attributes["Value"].Value);
                                nxtfolder.OrderBy = node2.Attributes["Orderby"] == null ? null : node2.Attributes["Orderby"].Value;

                                foreach (XmlNode node3 in node2.ChildNodes)
                                {
                                    if (node3.Name.ToUpper() == "SUBFOLDER")
                                    {
                                        nxtfolder.AddSubFolder(new SubFolderDefinition(
                                        node3.Attributes["Name"].Value,
                                        node3.Attributes["Column"].Value,
                                        node3.Attributes["ForeignColumn"].Value,
                                        node3.Attributes["Condition"] == null ? null : node3.Attributes["Condition"].Value));
                                    }
                                }

                                folders.Add(nxtfolder);
                            }
                        }
                        else if (node2.Name.ToUpper() == "ENUM")
                        {
                            enums.Add(new EnumFolderDefinition(node2.Attributes["Name"].Value,
                                        node2.Attributes["Table"].Value, node2.Attributes["Display"].Value,
                                        node2.Attributes["Value"].Value));
                        }
                    }
                }
            }
        }

        public void SaveFile()
        {
            XmlDocument myXmlDocument = new XmlDocument();
            myXmlDocument.Load(XmlFilePath);

            XmlNode rootNode;
            rootNode = myXmlDocument.DocumentElement;

            foreach (XmlNode node1 in rootNode.ChildNodes)
            {
                if (node1.Name.ToUpper() == "STRUCTURE")
                {
                    XmlNode structNode = myXmlDocument.CreateNode(XmlNodeType.Element, "Structure", "");

                    foreach (FolderDefinition fd in Folders)
                    {
                        XmlNode child = myXmlDocument.CreateNode(XmlNodeType.Element, "Folder", "");
                        XmlAttribute attributeName = myXmlDocument.CreateAttribute("Name");
                        XmlAttribute attributeTable = myXmlDocument.CreateAttribute("Table");
                        XmlAttribute attributeDisplay = myXmlDocument.CreateAttribute("Display");
                        XmlAttribute attributeValue = myXmlDocument.CreateAttribute("Value");
                        XmlAttribute attributeLevel = myXmlDocument.CreateAttribute("Level");

                        attributeName.Value = fd.Name;
                        attributeTable.Value = fd.TableName;
                        attributeDisplay.Value = fd.DisplayExp;
                        attributeValue.Value = fd.ValueExp;
                        if (fd.Level.Equals(FolderLevel.Four))
                        {
                            attributeLevel.Value = "4";
                            child.Attributes.Append(attributeName);
                            child.Attributes.Append(attributeTable);
                            child.Attributes.Append(attributeLevel);
                        }
                        else
                        {
                            switch (fd.Level)
                            {
                                case FolderLevel.One:
                                    attributeLevel.Value = "1";
                                    break;
                                case FolderLevel.Two:
                                    attributeLevel.Value = "2";
                                    break;
                                case FolderLevel.Three:
                                    attributeLevel.Value = "3";
                                    break;
                            }
                            child.Attributes.Append(attributeName);
                            child.Attributes.Append(attributeTable);
                            child.Attributes.Append(attributeDisplay);
                            child.Attributes.Append(attributeValue);
                            child.Attributes.Append(attributeLevel);
                        }
                        foreach (SubFolderDefinition sfd in fd.SubFolders)
                        {
                            XmlNode subNode = myXmlDocument.CreateNode(XmlNodeType.Element, "SubFolder", "");
                            XmlAttribute attributeSfName = myXmlDocument.CreateAttribute("Name");
                            XmlAttribute attributeSfColumn = myXmlDocument.CreateAttribute("Column");
                            XmlAttribute attributeSfForeignColumn = myXmlDocument.CreateAttribute("ForeignColumn");

                            attributeSfName.Value = sfd.Name;
                            attributeSfColumn.Value = sfd.Column;
                            attributeSfForeignColumn.Value = sfd.ForeignColumn;

                            subNode.Attributes.Append(attributeSfName);
                            subNode.Attributes.Append(attributeSfColumn);
                            subNode.Attributes.Append(attributeSfForeignColumn);
                            child.AppendChild(subNode);
                        }
                        structNode.AppendChild(child);
                    }

                    foreach (EnumFolderDefinition efd in EnumFolders)
                    {
                        XmlNode child = myXmlDocument.CreateNode(XmlNodeType.Element, "Enum", "");
                        XmlAttribute attributeName = myXmlDocument.CreateAttribute("Name");
                        XmlAttribute attributeTable = myXmlDocument.CreateAttribute("Table");

                        attributeName.Value = efd.Name;
                        attributeTable.Value = efd.TableName;
                        
                        child.Attributes.Append(attributeName);
                        child.Attributes.Append(attributeTable);

                        structNode.AppendChild(child);
                    }

                    rootNode.ReplaceChild(structNode, node1);
                    myXmlDocument.Save(XmlFilePath.Remove(0,8));
                    Init();
                    return;
                }
            }
            throw new Exception("File must contain a structure node.");
        }

        public void CancelChanges()
        {
            Init();
        }
        #endregion

    }
}
